package com.xinguan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinguan.dao.TbDepartmentDao;
import com.xinguan.dao.TbRoleDao;
import com.xinguan.dao.TbUserDao;
import com.xinguan.dao.TbUserRoleDao;
import com.xinguan.entity.TbDepartment;
import com.xinguan.entity.TbRole;
import com.xinguan.entity.TbUser;
import com.xinguan.entity.TbUserRole;
import com.xinguan.enums.system.UserStatusEnum;
import com.xinguan.enums.system.UserTypeEnum;
import com.xinguan.error.SystemCodeEnum;
import com.xinguan.error.SystemException;
import com.xinguan.response.ResponseBean;
import com.xinguan.service.TbUserService;
import com.xinguan.shiro.JWTToken;
import com.xinguan.utils.JWTUtil;
import com.xinguan.utils.MD5Util;
import com.xinguan.vo.system.UserEditVO;
import com.xinguan.vo.system.UserInfoVO;
import com.xinguan.vo.system.UserVO;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 郭经伟
 * @since 2021-07-10
 */
@Service
public class TbUserServiceImpl extends ServiceImpl<TbUserDao, TbUser> implements TbUserService {


    @Resource
    private TbUserDao userDao;

    @Resource
    private TbDepartmentDao departmentDao;


    @Resource
    private TbRoleDao roleDao;

    @Resource
    private TbUserRoleDao userRoleDao;

    /**
     * 锁
     */
    final transient ReentrantLock lock = new ReentrantLock();

    /**
     * 用户登入
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public String login(String username, String password) throws SystemException {
        String token;
        TbUser user = userDao.selectOne(new QueryWrapper<TbUser>().eq("username", username));
        if (user != null) {
            // 存在此用户

            // 1.获得user中的salt
            String salt = user.getSalt();
            String target = MD5Util.md5Encryption(password, salt);
            // 2.生成token
            token = JWTUtil.sign(username, target);
            JWTToken jwtToken = new JWTToken(token);
            try {
                SecurityUtils.getSubject().login(jwtToken);
            } catch (AuthenticationException e) {
                throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, e.getMessage());
            }
        } else {
            // 不存在此用户
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "用户不存在");
        }
        return token;
    }

    /**
     * 查询列表
     *
     * @param currentPage
     * @param pageSize
     * @param userVO
     * @return
     */
    @Override
    public ResponseBean findUserList(Integer currentPage, Integer pageSize, UserVO userVO) {
        // 分页查询
        IPage<UserVO> userVOList = userDao.findUserVOList(new Page<>(currentPage, pageSize), userVO);
        return ResponseBean.success(userVOList);

    }

    /**
     * 新增用户
     *
     * @param userVO
     */
    @Transactional
    @Override
    public void addUser(UserVO userVO) throws SystemException {
        // 首先判断当前User是否存在
        @NotBlank(message = "用户名不能为空") String username = userVO.getUsername();
        @NotNull(message = "部门id不能为空") Long departmentId = userVO.getDepartmentId();
        TbUser tbUser = userDao.selectOne(new QueryWrapper<TbUser>().eq("username", username));
        if (tbUser != null) {
            // 当前用户存在
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "当前用户存在");
        }
        TbDepartment tbDepartment = departmentDao.selectById(departmentId);
        if (tbDepartment == null) {
            // 当前部门不存在
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "当前部门不存在");
        }
        // 新增user
        TbUser user = new TbUser();
        BeanUtils.copyProperties(userVO, user);
        user.setCreateTime(new Date());
        user.setModifiedTime(new Date());
        // 设置密码加密的salt
        String salt = UUID.randomUUID().toString().substring(0, 32);
        user.setPassword(MD5Util.md5Encryption(userVO.getPassword(), salt));
        user.setSalt(salt);
        //添加的用户默认是普通用户
        user.setType(UserTypeEnum.SYSTEM_USER.getTypeCode());
        user.setStatus(UserStatusEnum.AVAILABLE.getStatusCode());
        user.setAvatar("http://badidol.com/uploads/images/avatars/201910/24/18_1571921832_HG9E55x9NY.jpg");
        userDao.insert(user);

    }

    @Transactional
    @Override
    public void deleteUser(Long id) throws SystemException {
        TbUser user = userDao.selectById(id);
        TbUser activeUser = (TbUser) SecurityUtils.getSubject().getPrincipal();
        if (user == null) {
            // 删除的用户不存在
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "删除的用户不存在");
        }

        if (activeUser.getId().equals(user.getId())) {
            // 不能删除当前登录用户
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "不能删除当前登入用户");
        }
        userDao.deleteById(id);
    }

    @Override
    public UserEditVO edit(Long id) throws SystemException {
        TbUser user = userDao.selectById(id);
        if (user == null) {
            // 要编辑的用户不存在
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "要编辑的用户不存在");
        }
        UserEditVO userEditVO = new UserEditVO();
        BeanUtils.copyProperties(user, userEditVO);
        TbDepartment department = departmentDao.selectById(user.getDepartmentId());
        if (department != null) {
            userEditVO.setDepartmentId(department.getId());
        }
        return userEditVO;
    }

    @Transactional
    @Override
    public void updateOneUser(Long id, UserEditVO userEditVO) throws SystemException {
        TbUser user = userDao.selectById(id);
        @NotNull(message = "部门不能为空") Long departmentId = userEditVO.getDepartmentId();
        if (user == null) {
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "要编辑的用户不存在");
        }
        TbDepartment tbDepartment = departmentDao.selectById(departmentId);
        if (tbDepartment == null) {
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "部门不存在");
        }
        userDao.update(null, new UpdateWrapper<TbUser>().eq("id", id)
                .set("nickname", userEditVO.getNickname())
                .set("email", userEditVO.getEmail())
                .set("phone_number", userEditVO.getPhoneNumber())
                .set("sex", userEditVO.getSex())
                .set("birth", userEditVO.getBirth())
                .set("department_id", userEditVO.getDepartmentId())
                .set("modified_time", new Date()));
    }

    @Transactional
    @Override
    public void updateUserStatus(Long id, Boolean status) throws SystemException {

        TbUser user = userDao.selectById(id);
        if (user == null) {
            // 当前user不存在
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "当前用户不存在");
        }
        TbUser tbUser = (TbUser) SecurityUtils.getSubject().getPrincipal();
        if (tbUser.getId().equals(user.getId())) {
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "无法改变当前用户状态");
        } else {
            // 这里传过来的status 是 是否
            if (status) {
                // 开启
                userDao.update(null, new UpdateWrapper<TbUser>().eq("id", id).set("status", UserStatusEnum.AVAILABLE.getStatusCode()));
            } else {
                userDao.update(null, new UpdateWrapper<TbUser>().eq("id", id).set("status", UserStatusEnum.DISABLE.getStatusCode()));
            }
        }
    }

    /**
     * 登录获得用户信息
     *
     * @return
     */
    @Override
    public UserInfoVO info() {
        return null;
    }

    /**
     * 分配角色
     * 事务外面加锁
     *
     * @param id   用户id
     * @param rids 分配的角色id数组
     * @throws SystemException
     */
    @Override
    public void assignRoles(Long id, Long[] rids) throws SystemException {
        Lock lock = this.lock;
        lock.lock();
        try {
            this.assignRoleTraditional(id, rids);
        } finally {
            lock.unlock();
        }
    }


    @Transactional
    void assignRoleTraditional(Long id, Long[] rids) throws SystemException {

        // 首先需要删除用户所有的角色
        TbUser user = userDao.selectById(id);
        if (user == null) {
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "用户不存在");
        }
        int deleteRows = userRoleDao.delete(new QueryWrapper<TbUserRole>().eq("user_id", user.getId()));
        if (deleteRows < 0) {
            // 删除失败
            throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "删除失败");
        }
        List<TbUserRole> userRoles = new ArrayList<>();
        if (rids.length > 0) {
            for (Long rid : rids) {
                TbRole role = roleDao.selectById(rid);
                if (role == null) {
                    throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "roleId=" + rid + ",该角色不存在");
                }
                // 判断角色状态
                if (role.getStatus() == 0) {
                    throw new SystemException(SystemCodeEnum.PARAMETER_ERROR, "roleName=" + role.getRoleName() + ",该角色已经禁用");
                }
                TbUserRole userRole = new TbUserRole();
                userRole.setRoleId(rid);
                userRole.setUserId(id);
                userRoles.add(userRole);
            }
        }
        // 再重新添加用户角色 批量insert
        userRoleDao.batchInsert(userRoles);
    }
}
